package com.qisu.command;

import java.util.Arrays;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;

import com.qisu.socket.server.ChannelList;

import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import io.netty.channel.ChannelHandlerContext;

/**
 *
 * @author alsan
 *
 */
public abstract class AbstractCommand implements Command {
	private String border = new String(new char[80]).replace("\0", "=");

	@Value("${packet.id.pos}") protected int pos;
	@Value("${packet.id.len}") protected int len;

	protected Log log = LogFactory.get();
	protected CommandFieldsList fieldsList;

	/**
	 * 报文命令处理
	 * @param req
	 * @throws Exception
	 */
	protected abstract void processCmd(ChannelHandlerContext ctx,byte[] req) throws Exception;
	
	/**
	 * 报文回复
	 * @param ctx
	 */
	protected abstract void responseClient(ChannelHandlerContext ctx);

	protected ChannelList channelList;

	@Autowired
	protected void setChannelList(ChannelList channelList) {
		this.channelList = channelList;
	}

	protected void init() {
		fieldsList = new CommandFieldsList();
	}

	protected void saveChannel(ChannelHandlerContext ctx, int cmd, byte[] req) {
		if(cmd >= 0xff80) {
			log.debug("command is from server, ignore this channel");
		} else {
			byte[] dt = Arrays.copyOfRange(req, pos, pos + len);
			StringBuffer buf = new StringBuffer();

			for(byte b : dt) {
				if(b >= 0x20 && b <= 0x80) {
					buf.append((char)b);
				}
			}

			channelList.put(buf.toString(), ctx);
		}
	}

	private void extractFields(byte[] req) {

		StringBuffer buf = new StringBuffer("\n");
		int pos = 0;
		int propCnt = 0;

		buf.append(border).append("\n");

		for(String id : fieldsList.getFieldIdList()) {
			CommandFieldDef<?> fieldDef = fieldsList.getDef(id);
			String description = fieldDef.getDescription();

			fieldDef.setPosition(pos);

			if(fieldDef.hasConverter()) {
				fieldDef.convert(req);
			}
			if(null != description) {
				buf.append(description).append("=").append(fieldDef.getValue());
				if(0 == (++propCnt % 10)) {
					buf.append("\n");
				} else {
					buf.append(", ");
				}
			}

			pos += fieldDef.getLength();
		}

		buf.append("\n").append(border).append("\n");

		log.info(buf.toString());
	}

	@Override
	public void proceed(ChannelHandlerContext ctx, int cmd, byte[] req) throws Exception {
		boolean isUnknownCommand = this instanceof CommandUnknown;
		
		if(!isUnknownCommand) {
			if(fieldsList.isInitialized()) {
				saveChannel(ctx, cmd, req);
				extractFields(req);
				processCmd(ctx,req);
				// 从processCmd里response
//				responseClient();
			} else {
				log.warn("command fields definitation not found");
			}
		}else {
			processCmd(ctx,req);
		}
	}
}
